﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

namespace QuickRunCore.Helper
{
    public class LogInfo
    {
        /// <summary>
        /// 日志保存的文件名
        /// </summary>
        public string LogFileName { get; set; }

        /// <summary>
        /// 日志内容
        /// </summary>
        public string LogMessage { get; set; }
    }

    /// <summary>
    /// 日志文件操作类
    /// </summary>
    public class LogHelper
    {
        /// <summary>
        /// 日志类型
        /// </summary>
        public enum LogType
        {
            /// <summary>
            /// 跟踪
            /// </summary>
            Trace,
            /// <summary>
            /// 日常记录信息
            /// </summary>
            Info,
            /// <summary>
            /// 警告
            /// </summary>
            Warning,
            /// <summary>
            /// 错误
            /// </summary>
            Error
        }

        /// <summary>
        /// 日志文件存放路径
        /// </summary>
        private static string logPath = string.Empty;

        /// <summary>
        /// 是否已经开始任务
        /// </summary>
        private static bool RunTask = false;

        ///<summary> 
        /// 保存日志的文件夹 
        ///</summary> 
        public static string LogPath()
        {
            if (logPath == string.Empty)
            {
                logPath = FileHelper.GetProcDir() + @"log\";
            }
            return logPath;
        }

        /// <summary>
        /// 运行记录日志
        /// </summary>
        public static void RunWriteLog()
        {
            RunTask = true;
            Task.Factory.StartNew(WriteLogFromQueue);
        }

        /// <summary>
        /// 信号
        /// </summary>
        private static readonly ManualResetEvent Semaphore = new ManualResetEvent(false);

        /// <summary>
        /// 日志队列
        /// </summary>
        private static readonly ConcurrentQueue<KeyValuePair<string, LogInfo>> LogQueue =
            new ConcurrentQueue<KeyValuePair<string, LogInfo>>();


        /// <summary>
        /// 从队列中写日志至磁盘
        /// </summary>
        private static void WriteLogFromQueue()
        {
            while (true)
            {
                // 等待信号通知
                Semaphore.WaitOne();

                // 判断是否有内容需要如磁盘 从列队中获取内容，并删除列队中的内容
                while (LogQueue.Count > 0 && LogQueue.TryDequeue(out var keyValuePairs))
                {
                    WriteLogToFile(keyValuePairs.Key, keyValuePairs.Value.LogMessage, keyValuePairs.Value.LogFileName);
                }

                // 重新设置信号
                Semaphore.Reset();
                Thread.Sleep(1);
            }
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="logType">日志文件类型</param>
        /// <param name="msg">日志内容</param>
        /// <param name="fileName">日志文件</param>
        [MethodImpl(MethodImplOptions.Synchronized)]
        public static void WriteLogToFile(string logType, string msg, string fileName = "Default")
        {
            try
            {
                string _filePath = LogPath() + logType + @"\";
                if (!Directory.Exists(_filePath))
                {
                    Directory.CreateDirectory(_filePath);
                }
                System.IO.File.AppendAllText(_filePath + fileName + DateTime.Now.ToString("yyyyMMdd") + ".Log",
                    msg);
            }
            catch
            {

            }
        }


        /// <summary>
        /// 将消息入列
        /// </summary>
        /// <param name="message"></param>
        /// <param name="level"></param>
        public static void WriteLog(LogType logType, string message, string fileName = "Default")
        {
            if (!RunTask)
            {
                RunWriteLog();
            }
            LogQueue.Enqueue(new KeyValuePair<string, LogInfo>(Enum.GetName(typeof(LogType), logType), new LogInfo { LogFileName = fileName, LogMessage = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff  ") + message + "\r\n" }));
            // 通知线程往磁盘中写日志
            Semaphore.Set();
        }

    }
}
